﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DriveBeamEditor.Annotations;
using DriveBeamEditor.Interfaces;
using JBeamLibrary.Tools;
using JBeamLibrary.Types;

namespace DriveBeamEditor.Controls.General
{
    public partial class Float3Edit : UserControl, IEditor, INotifyPropertyChanged
    {
        #region Fields

        public event EventHandler ValueChanged;
        public event EventHandler EditValueChanged;
        public event EventHandler EditableChanged;

        #endregion

        #region Properties

        public float X
        {
            get { return float.Parse(kvcX.EditValue.ToStringOrZero()); }
            set { kvcX.EditValue = value; }
        }

        public float Y
        {
            get { return float.Parse(kvcY.EditValue.ToStringOrZero()); }
            set { kvcY.EditValue = value; }
        }

        public float Z
        {
            get { return float.Parse(kvcZ.EditValue.ToStringOrZero()); }
            set { kvcZ.EditValue = value; }
        }

        public Float3 Float3
        {
            get { return new Float3(X, Y, Z); }
            set { EditValue = value; }
        }

        public object EditValue
        {
            get { return new Float3(X, Y, Z); }
            set
            {
                /* Reset values on null */
                if (value == null || value == System.DBNull.Value)
                {
                    X = 0f;
                    Y = 0f;
                    Z = 0f;
                    return;
                }

                /* Invalid type provided */
                if (!(value is Float3))
                    throw new ArgumentException(
                        string.Format("EditValue must take a Float3 object. Given object was of type {0}.", value.GetType().Name));

                /* Update values */
                var val = (Float3)value;
                X = val.X;
                Y = val.Y;
                Z = val.Z;

                /* Notify property change */
                OnPropertyChanged();
            }
        }

        public string Value
        {
            get { return EditValue != null ? EditValue.ToString() : null; }
            set
            {
                if (Value.Equals(value)) return;
                if (string.IsNullOrEmpty(value))
                    EditValue = null;
                else
                    EditValue = Float3.Parse(value);
                OnValueChanged();
            }
        }

        public bool Editable
        {
            get { return kvcX.Editable; }
            set
            {
                kvcX.Editable = value;
                kvcY.Editable = value;
                kvcZ.Editable = value;
                OnEditableChanged();
            }
        }

        public bool ReadOnly
        {
            get { return kvcX.ReadOnly; }
            set
            {
                kvcX.ReadOnly = value;
                kvcY.ReadOnly = value;
                kvcZ.ReadOnly = value;
            }
        }

        #endregion

        #region CTORs

        public Float3Edit()
        {
            InitializeComponent();
        }

        #endregion

        #region Events

        private void kvc_EditValueChanged(object sender, EventArgs e)
        {
            if (EditValueChanged != null)
                EditValueChanged(this, e);
        }

        #endregion

        #region Methods

        private void OnEditableChanged()
        {
            if (!Editable && Enabled) Enabled = false;

            if (EditableChanged != null)
                EditableChanged(this, new EventArgs());
        }

        private void OnValueChanged()
        {
            if (ValueChanged != null)
                ValueChanged(this, new EventArgs());
        }

        public void SetEditValueSilent(object value)
        {
            /* Reset values if null */
            if (value == null)
            {
                kvcX.SetEditValueSilent(0);
                kvcY.SetEditValueSilent(0);
                kvcZ.SetEditValueSilent(0);
                return;
            }

            /* Invalid value type */
            if (!(value is Float3))
                throw new ArgumentException(
                    string.Format("EditValue must take a Float3 object. Given object was of type {0}.", value.GetType().Name));

            /* Update editors */
            var val = (Float3)value;
            kvcX.SetEditValueSilent(val.X);
            kvcY.SetEditValueSilent(val.Y);
            kvcZ.SetEditValueSilent(val.Z);
        }

        #endregion

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

    }
}
